import { _decorator, Component, EventTouch, instantiate, Node, NodeEventType, NodePool, Prefab, SpriteAtlas, SpriteFrame, tween, Tween, UITransform, v2, v3, Vec3, Widget } from 'cc';
import { $planet_DISTANCE_DIFF_poof$, $planet_PLANET_CONF_poof$, $planet_PLANET_GENERATE_CONF_poof$, $planet_PLANET_ID_LIST_poof$, $planet_PLANET_SPRITE_poof$ } from '../../config.global';
import { Planet } from '../../src/element/planet';
import { $planet_AudioManager_poof$ } from '../../src/manager/audio-manager';
import $planet_GameDC_poof$ from '../data/game.data.center';
import { $planet_GameFloat_poof$ } from './game.float';
const { ccclass, property } = _decorator;

@ccclass('GamePlanetContainer')
export class GamePlanetContainer extends Component {
	@property(Prefab)
	private planet_prefab: Prefab = null;
	@property(SpriteAtlas)
	private planet_atlas: SpriteAtlas = null;

	private $planet_ui_canvas_poof$: UITransform;
	private $planet_ui_container_poof$: UITransform;
	private $planet_sprite_planet_map_poof$: Map<string, SpriteFrame>;

	private $planet_planet_pool_poof$ = new NodePool(Planet);
	private $planet_check_dead_count_poof$: number = Infinity;
	/** 球球合成中…… */
	private $planet_fusing_poof$ = false;

	public get $planet_top_poof$(){
		return this.$planet_ui_container_poof$.height * (1-this.$planet_ui_container_poof$.anchorY);
	}
	/** 容器中的球球数据 */
	public get $planet_container_data_poof$(){
		let group = new Map<typeof $planet_PLANET_ID_LIST_poof$[number], number>();
		this.$planet_ui_container_poof$.getComponentsInChildren(Planet).forEach(p=>{
			group.set(p.$planet_data_poof$.id, (group.get(p.$planet_data_poof$.id)??0)+1);
		});

		return group;
	}
	/** 容积率 */
	public get $planet_plot_ratio_poof$(){
		return this.$planet_ui_container_poof$.getComponentsInChildren(Planet).reduce((t, p)=>t+p.$planet_data_poof$.area, 0) / this.$planet_ui_container_poof$.width / this.$planet_ui_container_poof$.height;
	}

	/** 球球生成中 */
	private $planet_generating_poof$: boolean = false;

    start() {
		this.$planet_init_poof$();
    }

    update(deltaTime: number) {
		if(this.$planet_check_dead_count_poof$>0) this.$planet_check_dead_count_poof$ -= deltaTime;
		else{
			this.$planet_check_dead_count_poof$ = 1;
			this.$planet_checkDeath_poof$();
		}
    }

	private $planet_adaptUI_poof$(){
		let wgt = this.$planet_ui_container_poof$.getComponent(Widget);
		if(wgt){
			wgt.bottom = 430;
			wgt.top = 300 + (abd.$planet_cc_poof$.$planet_is_long_screen_poof$ ? 100 : 0);
			wgt.updateAlignment();
		}
	}

	private $planet_init_poof$(){
		[this.$planet_ui_canvas_poof$, this.$planet_ui_container_poof$] = [abd.$planet_cc_poof$.$planet_canvas_poof$.node, this.node.getChildByName('planet')].map(n=>n.getComponent(UITransform));
		this.$planet_sprite_planet_map_poof$ = new Map(this.planet_atlas.getSpriteFrames().map(sframe=>[sframe.name, sframe]));

		$planet_PLANET_ID_LIST_poof$.map(id=>this.$planet_createPlanet_poof$(id, false)).forEach(p=>this.$planet_recyclePlanet_poof$(p));

		this.$planet_adaptUI_poof$();

		this.node.on(NodeEventType.TOUCH_END, this.$planet_touchEnd_poof$, this);

		let guided = Boolean(localStorage.getItem('UExBTkVULVBPT0YtS0lORy1HVUlERQ=='));

		$planet_GameDC_poof$.$planet_follow_poof$('$planet_trigger_poof$', '$planet_RESET_poof$', (o, v)=>{
			if(v==o || !v) return void 0;
			this.$planet_refreshPlanet_poof$().then(()=>{
				$planet_GameDC_poof$.$planet_trigger_poof$.$planet_RESET_poof$ = false;
			});
		}, false);
		$planet_GameDC_poof$.$planet_follow_poof$('$planet_trigger_poof$', '$planet_LOAD_GAME_poof$', ()=>{
			let prms = this.$planet_run_poof$();
			if(!guided) prms = prms.then(()=>new Promise(s=>this.scheduleOnce(()=>this.$planet_guide_poof$().then(()=>s('end')), 0.8)));
		}, false);

	}

	private $planet_saveData_poof$(...param: Array<typeof this.$planet_container_data_poof$>){
		let data = Array.from($planet_PLANET_ID_LIST_poof$.filter(id=>id!==11).reduce((m, id)=>{
			m.set(id, param.reduce((count, data_map)=>count+(data_map.get(id)??0), 0));
			return m;
		}, new Map() as typeof this.$planet_container_data_poof$));

		if(data.reduce((t, el)=>t+el[1], 0)<=0) return void 0;

		abd.$planet_local_poof$.$planet_save_poof$('planet-data', data);
	}

	private $planet_createPlanet_poof$(id?: typeof $planet_PLANET_ID_LIST_poof$[number], red?: boolean){
		//let node: Node;
		//if(this.$planet_planet_pool_poof$.size() > 0) node = this.$planet_planet_pool_poof$.get();
		//else node = instantiate(this.planet_prefab);

		let node = instantiate(this.planet_prefab);

		node.setParent(this.$planet_ui_container_poof$.node);

		let planet = node.getComponent(Planet);
		if(id!==undefined) planet.$planet_setPlanet_poof$({id, spriteFrame: this.$planet_sprite_planet_map_poof$.get($planet_PLANET_SPRITE_poof$[id]), red});

		node.setPosition(this.$planet_ui_container_poof$.convertToNodeSpaceAR(v3(
			(Math.random()*this.$planet_ui_canvas_poof$.contentSize.width/2-planet.$planet_width_poof$) * (Math.random()<0.5?-1:1) + this.$planet_ui_canvas_poof$.node.position.x,
			this.$planet_ui_canvas_poof$.height * 0.6 + this.$planet_ui_canvas_poof$.node.position.y,
			//this.$planet_ui_canvas_poof$.node.position.y+300,
			0
		)));

		return planet;
	}

	private $planet_recyclePlanet_poof$(planet: Planet){
		this.$planet_planet_pool_poof$.put(planet.node);
	}

	private $planet_upgradePlanet_poof$(planet: Planet){
		if(!planet.isValid) return planet;
		let index = Math.min($planet_PLANET_ID_LIST_poof$.indexOf(planet.$planet_data_poof$.id)+1, $planet_PLANET_ID_LIST_poof$.length-1);
		let id = $planet_PLANET_ID_LIST_poof$[index];
		planet.$planet_setPlanet_poof$({id, spriteFrame: this.$planet_sprite_planet_map_poof$.get($planet_PLANET_SPRITE_poof$[id])});
		return planet;
	}

	private $planet_fullingPlanet_poof$(planet: Planet){
		// @ts-ignore
		planet.$planet_wakeUp_poof$(this);
		return planet;
	}

	private $planet_generatePlanet_poof$(data: Map<typeof $planet_PLANET_ID_LIST_poof$[number], number>){
		this.$planet_generating_poof$ = true;
		let np = new abd.$planet_NudityPromise_poof$<'end'>();
		this.$planet_saveData_poof$(this.$planet_container_data_poof$, data);
		let frame = abd.$planet_cc_poof$.$planet_frameTime_poof$/1000;

		let list = Array.from(data);
		if(list.length>0){
			let total = list.reduce((acc, el)=>acc+el[1], 0);
			let index = 0;
			let count = list[index][1];
			let id = list[index][0];
			this.schedule(()=>{
				while(!(count>0)){
					index++;
					if(index>=list.length){
						np.$planet_resolve_poof$('end');
						break;
					}
					count = list[index][1];
					id = list[index][0];
				}

				if(count>0){
					this.$planet_fullingPlanet_poof$(this.$planet_createPlanet_poof$(id, false));
					count--;
				}
			}, frame, total);
		}else np.$planet_resolve_poof$('end');

		np.$planet_promise_poof$.then(()=> this.$planet_generating_poof$ = false );

		return np.$planet_promise_poof$;
	}

	private $planet_run_poof$(){
		let data = abd.$planet_local_poof$.$planet_read_poof$<[typeof $planet_PLANET_ID_LIST_poof$[number], number][]>('planet-data');
		let promise = this.$planet_generatePlanet_poof$(new Map(data ?? [[1, 32]]));
		this.$planet_check_dead_count_poof$ = 1;
		return promise;
	}

	private touch_record = {location: v2()}
	private $planet_touchEnd_poof$(event: EventTouch){
		if(this.$planet_fusing_poof$ || this.$planet_generating_poof$ || this.$planet_guiding_poof$) return void 0;
		event.getUILocation(this.touch_record.location);

		let planet = this.$planet_findPlanet_poof$(abd.$planet_cc_poof$.$planet_v3_poof$(this.touch_record.location, 0));
		if(planet) this.$planet_goFusion_poof$(planet);
	}

	private async $planet_goFusion_poof$(planet: Planet){
		$planet_AudioManager_poof$.$planet_ins_poof$.$planet_playEffect_poof$($planet_AudioManager_poof$.$planet_EFFECT_poof$.$planet_PLANET_poof$);
		let list = this.$planet_getAdjoinPlanet_poof$(planet);
		if(list.length <= 1) return void 0;
		list.forEach(p=>p.$planet_sleep_poof$());
		let origin_id = list[0].$planet_data_poof$.id;

		// @ts-ignore
		planet.$planet_wakeUp_poof$(this);
		let statistics = await this.$planet_fusionPlanet_poof$(planet, list);

		abd.$planet_log_poof$.$planet_tag_poof$((<const>[
			['本次合成，连击>>', abd.$planet_string_poof$.$planet_normalLen_poof$(statistics.hit, 3)],
			['得分>>', abd.$planet_string_poof$.$planet_normalLen_poof$(statistics.score, 4)],
			['初始球球>>', abd.$planet_string_poof$.$planet_normalLen_poof$(origin_id, 4)],
			['最终合成球>>', abd.$planet_string_poof$.$planet_normalLen_poof$(statistics.id, 4)],
			['最终容积率>>', abd.$planet_number_poof$.$planet_fixedNum_poof$(this.$planet_plot_ratio_poof$, 4).toString().padEnd(6, '0')],
			['本次场上球球>>', '统计数据>>']
		]).map(_=>_[0]+':beige;'+_[1]+':lime').join(';'), this.$planet_container_data_poof$);

		if(statistics.id >= $planet_GameDC_poof$.$planet_target_planet_poof$) $planet_GameDC_poof$.$planet_nextTargetPlanet_poof$();
		$planet_GameDC_poof$.$planet_user_poof$.$planet_fusionCount_poof$++;

		await $planet_GameFloat_poof$.$planet_Good_poof$(statistics.hit);

		if(statistics.id>=11) this.$planet_ELSB_poof$(planet);
		this.$planet_saveData_poof$();
		this.$planet_fillPlanet_poof$();
	}

	private find_temp = {position: v3(), distance: v3()};
	private $planet_findPlanet_poof$(world_position: Vec3){
		this.$planet_ui_container_poof$.convertToNodeSpaceAR(world_position, this.find_temp.position);
		let planet: Planet;
		for(let i = 0; i < this.$planet_ui_container_poof$.node.children.length; i++){
			let p = this.$planet_ui_container_poof$.node.children[i].getComponent(Planet);
			Vec3.subtract(this.find_temp.distance, this.find_temp.position, p.node.position);
			if(this.find_temp.distance.length() > Math.max(p.$planet_width_poof$, p.$planet_height_poof$)/2) continue;
			planet = p;
			break;
		}
		return planet;
	}

	private $planet_refreshing_poof$ = false;
	private async $planet_refreshPlanet_poof$(){
		this.$planet_refreshing_poof$ = true;
		$planet_GameFloat_poof$.$planet_showResetting_poof$();
		let data = this.$planet_container_data_poof$;
		this.$planet_ui_container_poof$.getComponentsInChildren(Planet).forEach(p=>this.$planet_recyclePlanet_poof$(p));
		//[...this.$planet_ui_container_poof$.node.children].forEach(n=>this.$planet_planet_pool_poof$.put(n));

		await this.$planet_generatePlanet_poof$(data);
		$planet_GameFloat_poof$.$planet_hideResetting_poof$();
		this.$planet_refreshing_poof$ = false;
	}

	private $planet_fillPlanet_poof$(){
		let ratio = 1-this.$planet_plot_ratio_poof$;
		if(ratio<=0.5) return void 0;

		let fill_area = this.$planet_ui_container_poof$.width * this.$planet_ui_container_poof$.height * ratio * 0.45;

		let fill_data: typeof this.$planet_container_data_poof$ = new Map();

		let count_area = 0;
		let rate_conf = [...$planet_PLANET_GENERATE_CONF_poof$.count_rate];
		let area_conf = new Map($planet_PLANET_CONF_poof$.map(el=>[el.id, el.area]));
		let max = Math.max(...$planet_PLANET_GENERATE_CONF_poof$.count_range);
		while(count_area < fill_area && rate_conf.length>0){
			let id = abd.$planet_drawLots_poof$(rate_conf);
			count_area += area_conf.get(id);
			if(!fill_data.has(id)) fill_data.set(id, 0);
			fill_data.set(id, fill_data.get(id)+1);
			if(fill_data.get(id)>=max) abd.$planet_array_poof$.$planet_remove_poof$(rate_conf, el=>el[0]==id);
		}

		//abd.$planet_log_poof$.$planet_tag_poof$('生成填充球球的数据:skyblue', fill_data);

		return this.$planet_generatePlanet_poof$(fill_data);
	}

	private $planet_getAdjoinPlanet_poof$(planet: Planet){
		let distance = Math.min(planet.$planet_width_poof$, planet.$planet_height_poof$) + $planet_DISTANCE_DIFF_poof$;

		let list = this.$planet_ui_container_poof$.node.children.filter(n=>n.name === planet.node.name);

		if(list.length <= 0) return [];

		let bucket: Node[] = [];
		let basket = [planet.node];
		let temp_vec = v3();

		while(basket.length>0){
			basket.forEach(n=>abd.$planet_array_poof$.$planet_remove_poof$(list, n));
			bucket.push(...basket);
			basket = list.reduce((ls, n)=>{
				for(let b of basket){
					Vec3.subtract(temp_vec, b.position, n.position);
					if(temp_vec.length() > distance) continue;
					ls.push(n);
				}
				return ls;
			}, [] as Node[]);
		}

		return bucket.map(n=>n.getComponent(Planet)).filter(p=>!p.$planet_is_sleep_poof$);
	}

	private $planet_randomAdjoinPlanet_poof$(){
		let group: Map<string, Planet[]> = new Map();
		this.$planet_ui_container_poof$.node.children.forEach(n=>{
			if(!group.has(n.name)) group.set(n.name, []);
			group.get(n.name).push(n.getComponent(Planet));
		});

		let possible: Planet[][] = [];
		group.forEach(ls=>ls.length>1 ? possible.push(ls) : void 0);

		if(possible.length===0) return {single: true, list: undefined};

		let temp_vec = v3();
		let list = possible.find(ls=>{
			let link = false;
			let distance = Math.min(ls[0].$planet_width_poof$, ls[0].$planet_height_poof$) + $planet_DISTANCE_DIFF_poof$;

			for(let planet of ls){
				if(ls.find(p=>p!=planet && Vec3.subtract(temp_vec, p.node.position, planet.node.position).length()<=distance)){
					link = true;
					break;
				}
			}

			return link;
		});

		return {single: false, list};
	}

	private $planet_fusionPlanet_poof$(target: Planet, list: Planet[], max_level?: number, statistics?: __fusion_statistics__, np?: abd.$planet_NudityPromise_poof$<__fusion_statistics__>){
		if(!statistics) statistics = {id: 1, hit: 0, score: 0};

		if(list.length<=1){
			statistics.id = target.$planet_data_poof$.id;
			statistics.score = target.$planet_data_poof$.score;
			np.$planet_resolve_poof$(statistics);
			// @ts-ignore
			list.forEach(p=>p.$planet_data_poof$.id!==11 ? p.$planet_wakeUp_poof$(this) : void 0);
		}else{
			if(!np){
				this.$planet_fusing_poof$ = true;
				np = new abd.$planet_NudityPromise_poof$();
				np.$planet_promise_poof$.then(()=>this.$planet_fusing_poof$ = false);
			}
			if(max_level===undefined) max_level = Math.min(target.$planet_data_poof$.max_level, $planet_GameDC_poof$.$planet_target_planet_poof$);

			list.sort((a, b)=>{
				let [power_a, power_b] = [a, b].map(p=>p.node.position.x * 1000 + p.node.position.y);
				return power_a - power_b;
			});

			let group: Planet[][] = [];
			list.forEach((p, i)=>{
				let index = Math.floor(i/2);
				if(group[index]) group[index].push(p);
				else group[index] = [p];
			});

			if(group.$planet_lastElement_poof$.length==1){
				let p = group.pop().pop();
				group.$planet_lastElement_poof$.push(p);
			}

			statistics.hit += group.length;

			Promise.all(group.map(g=>this.$planet_fusionEffect_poof$(target, g, g[0].$planet_data_poof$.id < max_level, 0.15)))
			.then(ls=>this.$planet_fusionPlanet_poof$(target, ls, max_level, statistics, np));
		}

		return np.$planet_promise_poof$;
	}

	private $planet_fusionEffect_poof$(target: Planet, group: Planet[], upgrade?: boolean, duration?: number){
		$planet_AudioManager_poof$.$planet_ins_poof$.$planet_playEffect_poof$($planet_AudioManager_poof$.$planet_EFFECT_poof$.$planet_SYNTHETIC_poof$);
		duration = duration ?? 0.6;
		upgrade = upgrade ?? false;
		let [root, ...other] = group.sort((a, b)=>abd.$planet_vector_poof$.$planet_distance_poof$(a.node.position, target.node.position) - abd.$planet_vector_poof$.$planet_distance_poof$(b.node.position, target.node.position));

		// @ts-ignore
		root.$planet_wakeUp_poof$(this);
		other.forEach(p=>{
			Tween.stopAllByTarget(p.node);
			tween(p.node)
			.to(duration, {position: root.node.position, scale: Vec3.ZERO})
			.call(()=>{
				this.$planet_recyclePlanet_poof$(p);
				p.node.scale.set(Vec3.ONE);
			}).start();
		});

		return new Promise<Planet>(s=>this.scheduleOnce(()=>{
			if(upgrade) this.$planet_upgradePlanet_poof$(root);
			s(root);
		}, duration));
	}

	private $planet_checkDeath_poof$(){
		if(this.$planet_fusing_poof$ || this.$planet_generating_poof$ || this.$planet_refreshing_poof$) return void 0;

		let data = this.$planet_randomAdjoinPlanet_poof$();
		if(data.single) this.$planet_fillPlanet_poof$();
		else if(!data.list) this.$planet_refreshPlanet_poof$();
	}

	private async $planet_ELSB_poof$(planet: Planet){
		planet.$planet_shutdown_poof$();
		$planet_GameFloat_poof$.$planet_setElsb_poof$(planet.node);
		$planet_GameDC_poof$.$planet_trigger_poof$.$planet_NEW_ELSB_poof$ = planet.$planet_data_poof$.id;
	}

	private $planet_guiding_poof$ = false;
	private async $planet_guide_poof$(){
		this.$planet_guiding_poof$ = true;
		let list = this.$planet_randomAdjoinPlanet_poof$().list;
		let comp = await import('./game.guide').then(m=>m.$planet_GameGuide_poof$);
		$planet_GameFloat_poof$.$planet_pointerTo_poof$(list[0].node);
		await comp.$planet_showGroup_poof$(list.map(p=>p.node));
		this.$planet_goFusion_poof$(list[0]);
		$planet_GameFloat_poof$.$planet_hidePointer_poof$();
		let node = comp.$planet_ins_poof$.node;
		node.removeFromParent();
		node.destroy();
		localStorage.setItem('UExBTkVULVBPT0YtS0lORy1HVUlERQ==', '1008001820');
		this.$planet_guiding_poof$ = false;
	}
}

type __fusion_statistics__ = {
	id: typeof $planet_PLANET_ID_LIST_poof$[number];
	score: number;
	hit: number;
}

